{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# __getattr__和__setattr__等方法\n",
    "\n",
    "1. `__getattribute__(self, name)`:在属性被访问时自动调用；\n",
    "2. `__getattr__(self, name)`:在属性被访问而对象没有这样的属性时自动调用\n",
    "3. `__setattr__(self, name, value)`:试图给属性赋值时调用\n",
    "4. `__delattr__(self, name)`:试图删除属性时，自动调用\n",
    "\n",
    "相比函数`property`，这些魔法方法使用起来要棘手些（从某种程度上说，效率也更低），但它们很有用，因为你可在这些方法中编写处理多个特性的代码。然而，在可能的情况下，还是使用函数property吧."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'Rectangle' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-5-a298856e3251>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m  \u001b[0mRectangle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 19\u001b[1;33m \u001b[0ms\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'size'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m100\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m500\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     20\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"size: \"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0ms\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'size'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: 'Rectangle' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "class Rectangle(object):\n",
    "    def __init__(self):\n",
    "        self.width = 0\n",
    "        self.height = 0\n",
    "        \n",
    "    def __setattr__(self, name, value):\n",
    "        if name == 'size':\n",
    "            self.width, self.height = value\n",
    "        else:\n",
    "            self.__dict__[name] = value\n",
    "            \n",
    "    def __getattr__(self, name):\n",
    "        if name == 'size':\n",
    "            return self.width, self.height\n",
    "        else:\n",
    "            raise AttributeError()\n",
    "            \n",
    "# 为什么调用是错误的呢？\n",
    "s =  Rectangle()\n",
    "s['size'] = 100, 500\n",
    "print(\"size: \", s['size'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编写方法`__setattr__`时需要避开无限循环陷阱，编写`__getattribute__`时亦如此。由于它拦截对所有属性的访问（在新式类中），因此将拦截对`__dict__`的访问！在 `__getattribute__`中访问当前实例的属性时，唯一安全的方式是使用超类的方法`__getattribute__`（使用`super`）"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
